//
//  WmcUploadManager.swift
//  YPWatermarkCamera
//
//  Created by 赵新 on 2022/5/27.
//

import Alamofire
import NSObject_Rx
import RxRelay
import RxSwift
import UIKit
import YPNetwork

// MARK: - [WmcUploadManager]

open class WmcUploadManager: NSObject {
    public static func uploadFile(data: Data,
                                  params: WmcUploadFileModel,
                                  appId: String? = nil,
                                  progress: ((Double) -> Void)? = nil,
                                  completion: ((WmcMediaUploadResourceModel) -> Void)? = nil,
                                  failure: ((YPNetworkError) -> Void)? = nil)
    {
        guard let paramsDict = params.toJSON() else { return }

        WmcMediaUploadAPI.applyUploadUrl(paramsDict: paramsDict, appId: appId) { model in
            WmcMediaUploadAPI.uploadImage(data: data, uploadUrl: model.uploadUrl, header: model.headers) { value in
                progress?(value)
            } completion: {
                completion?(model)
            } failure: { error in
                failure?(error)
            }
        } failure: { error in
            let err = YPNetworkError.uploadMapping(error?.localizedDescription ?? "网络请求失败")
            WmcLogManager.DebugLog(type: .mediaRequest, log: err.localizedDescription)
            failure?(err)
        }
    }

    public static func uploadFile(fileURL: URL,
                                  params: WmcUploadFileModel,
                                  appId: String? = nil,
                                  progress: ((Double) -> Void)? = nil,
                                  completion: ((WmcMediaUploadResourceModel) -> Void)? = nil,
                                  failure: ((YPNetworkError) -> Void)? = nil)
    {
        guard let paramsDict = params.toJSON() else { return }

        WmcMediaUploadAPI.applyUploadUrl(paramsDict: paramsDict, appId: appId) { model in
            WmcMediaUploadAPI.uploadImage(fileURL: fileURL, uploadUrl: model.uploadUrl, header: model.headers) { value in
                progress?(value)
            } completion: {
                completion?(model)
            } failure: { error in
                failure?(error)
            }
        } failure: { error in
            let err = YPNetworkError.uploadMapping(error?.localizedDescription ?? "网络请求失败")
            failure?(err)
        }
    }

    public static func uploadMultiFiles(_ models: [WmcUploadMultiFileProtocol],
                                        maxConcurrency: Int? = nil,
                                        progress: ((Double) -> Void)? = nil,
                                        completion: (([WmcMediaUploadResourceModel]) -> Void)? = nil,
                                        failure: ((YPWmcError) -> Void)? = nil)
    {
        // 设置总数
        var total = models.count

        if total == 0 {
            let error = YPWmcError(errorType: .requestError, info: "任务不能为空")
            failure?(error)
            return
        }

        // 请求参数
        var paramsDictList: [[String: Any]] = []
        // 进度列表
        var progressList: [Double] = []

        models.forEach { model in
            if let paramsDict = model.params?.toJSON() {
                paramsDictList.append(paramsDict)
                progressList.append(0.0)
            }
        }

        if paramsDictList.count != total {
            let error = YPWmcError(errorType: .requestError, info: "参数错误")
            failure?(error)
            return
        }

        WmcMediaUploadAPI.applyBatchUploadUrl(paramsDictList: paramsDictList) { resourceList in
            if resourceList.count != total {
                let error = YPWmcError(errorType: .requestError, info: "参数错误")
                failure?(error)
                return
            }

            // 默认最大线程数量
            var concurrencyCount = 9
            // 已上传的个数
            var uploadedCount = 0

            if let maxConcurrency = maxConcurrency, concurrencyCount > 0, concurrencyCount < 21 {
                concurrencyCount = maxConcurrency
            }
            let semaphore = DispatchSemaphore(value: concurrencyCount)
            let uuid = UUID().uuidString
            let label = "wmc.queue.multiFilesUpload.\(uuid)"
            let queue = DispatchQueue(label: label, attributes: .concurrent)

            queue.async {
                for (idx, resourceModel) in resourceList.enumerated() {
                    var uploadModel = models[idx]

                    guard let fileURL = uploadModel.fileURL else { return }

                    var request: Request?

                    uploadModel.cancel = {
                        progressList[idx] = 0.0
                        total -= 1
                        request?.cancel()
                        uploadModel.uploadStatus?(.cancel)
                        semaphore.signal()
                    }

                    semaphore.wait()

                    request = WmcMediaUploadAPI.uploadImage(fileURL: fileURL, uploadUrl: resourceModel.uploadUrl, header: resourceModel.headers) { value in
                        uploadModel.progress?(value)
                        progressList[idx] = value

                        var totalProgress: Double = 0.0
                        progressList.forEach { taskProgress in
                            totalProgress += taskProgress
                        }

                        let result = totalProgress / Double(total)
                        progress?(result)
                    } completion: {
                        uploadedCount += 1
                        uploadModel.uploadResult?(resourceModel)
                        uploadModel.uploadStatus?(.completion)
                        if uploadedCount == total {
                            completion?(resourceList)
                        }
                        semaphore.signal()
                    } failure: { error in
                        let err = YPWmcError(errorType: .serviceError, info: error.localizedDescription)
                        failure?(err)
                        uploadModel.uploadStatus?(.failure)
                        semaphore.signal()
                    }

                    uploadModel.uploadStatus?(.uploading)
                }
            }
        } failure: { error in
            let err = YPWmcError(errorType: .serviceError, info: error?.localizedDescription ?? "申请上传资源失败")
            failure?(err)
        }
    }
}
